AnimatedWidget
记得不记得在 Android 中 View 有一个方法 animate()
?它免去了我们写 ValueAnimator、获取值、在更新 UI 等一系列操作,直接调用 View 的 animate 方法即可,简化了操作。
在之前的例子中,我们需要为 AnimationController 添加监听器,然后再里面在调用 setState
来更新 UI,在 Flutter 中,也有个帮助我们简化动画操作的 Widget —— AnimatedWidget,它的使用方法也十分简单(这不废话么,使用复杂还不如直接使用 AnimationController):
- 创建
AnimatedWidget
子类 - 其构造方法需要一个
Listenable
对象参数 - 在 build 方法中返回需要执行动画的内容,其属性直接使用
Listenable
对象获取 - 在 State 的 build 方法中,直接 return 第一步创建的对象即可。
Listenable 是什么呢?它是一个抽象类,Animation 是它的实现类,这下明白了吧
所以之前的例子就可以这样写:
class AnimationRouteState extends State<AnimationRoute>
with TickerProviderStateMixin {
Animation<Color> animation;
AnimationController controller;
initState() {
super.initState();
controller = new AnimationController(
duration: const Duration(seconds: 3), vsync: this);
animation = new ColorTween(begin: Colors.lightGreenAccent, end: Colors.red)
.animate(controller);
controller.addListener((){
if(controller.isCompleted){
controller.repeat(reverse: true);
}
});
//启动动画
controller.forward();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return AnimatedColor(
animation: animation,
);
}
}
class AnimatedColor extends AnimatedWidget {
AnimatedColor({Key key, Animation<Color> animation})
: super(key: key, listenable: animation);
@override
Widget build(BuildContext context) {
Animation<Color> animation = listenable;
return Container(
color: animation.value,
alignment: Alignment.center,
width: 400,
height: 400,
);
}
}
效果如下:
总结一下,AnimatedWidget 其实相当于是 Animation 的一个包装类,省去了我们手动 setState。
AnimatedBuilder
在上面的例子中,AnimationRouteState
的 build
方法直接返回了 AnimatedColor
对象,试想一下这种情况,我们的布局是一个 Container
包含了一个 Text
,我们想要动态改变 Container 的背景色,按照 AnimatedWidget 的方法就是我们每次更新背景色都需要连同 Text 一起重新绘制,有一种牵一发而动全身的感觉,这样就比较耗费资源,使用 AnimatedBuilder 可以避免这种过度绘制。
AnimatedBuilder 的使用方法也很简单,它有三个参数:
animation
,必填参数,作用于控件上的动画builder
,必填参数,传入一个 build 方法自定义动画起作用的控件child
,该参数不是必填参数,如果不为 null,则该控件可以作为子控件添加到 builder 返回的 Widget 中,但它只绘制一次
看例子:
class AnimationRouteState extends State<AnimationRoute>
with TickerProviderStateMixin {
Animation<Color> animation;
AnimationController controller;
initState() {
super.initState();
controller = new AnimationController(
duration: const Duration(seconds: 1), vsync: this);
animation = new ColorTween(begin: Colors.lightGreenAccent, end: Colors.red)
.animate(controller);
controller.addListener(() {
if (controller.isCompleted) {
controller.repeat(reverse: true);
}
});
//启动动画
controller.forward();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text(""),
),
body: AnimatedBuilder(
animation: animation,
builder: (BuildContext context,Widget child){
return Container(
width: 400,
height: 400,
alignment: Alignment.center,
color: animation.value,
//这个 child 只会绘制一次
child: child,
);
},
child: Text("这个文本不会重复绘制",style:TextStyle(fontSize: 50)),
),
);
}
}
其效果是这样的: